package nio;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

/**
 * Created by GanJc on 2015/11/15.
 */
public class TimeServer  {

    private static final Logger logger = LoggerFactory.getLogger(TimeServer.class);

    public static void main(String[] args) {
        int port = 8888 ;
        MultiplexerTimeServer server = new MultiplexerTimeServer(port);
        new Thread(server,"nio-timeServer").start();
    }

    private static class MultiplexerTimeServer implements Runnable{

        private Selector selector ;

        private ServerSocketChannel serverSocketChannel ;

        private volatile boolean stop ;

        public MultiplexerTimeServer(int port) {
            try {
                //初始化多路复用器
                selector = Selector.open();
                //初始化server管道
                serverSocketChannel = ServerSocketChannel.open();
                //设置为非阻塞io
                serverSocketChannel.configureBlocking(false);
                //获取serverSocket 绑定端口
                serverSocketChannel.socket().bind(new InetSocketAddress(port),1024);
                serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
                logger.info("the timeServer is start in port {}",port);
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(1);
            }
        }

        public void stop(){
            this.stop = true ;
        }

        @Override
        public void run() {
            while (!stop){
                try {
                    selector.select(1000);
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while (iterator.hasNext()){
                        SelectionKey key = iterator.next();
                        iterator.remove();
                        try{
                            handleInput(key);
                        }catch (Exception e){
                            key.cancel();
                            if (key.channel()!=null){
                                key.channel().close();
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            IOUtils.closeQuietly(selector);
        }

        private void handleInput(SelectionKey key) throws IOException {
            if(key.isValid()){
                //处理新接入的请求消息
                if(key.isAcceptable()){
                    //接受新连接
                    ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = ssc.accept();
                    socketChannel.configureBlocking(false);
                    //把新的连接注册到selector
                    socketChannel.register(selector,SelectionKey.OP_READ);
                }
                if(key.isReadable()){
                    //读取数据
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    int read = socketChannel.read(byteBuffer);
                    if(read>0){
                        byteBuffer.flip();
                        byte[] bytes = new byte[byteBuffer.remaining()];
                        byteBuffer.get(bytes);
                        String body = new String(bytes, "utf-8");
                        logger.info("the timeServer receive order : {}" ,body);
                        String response ;
                        if("TIME".equals(body)){
                            response = "当前时间:" + new Date();
                        }else {
                            response = "BAD ORDER!" ;
                        }
                        doWrite(socketChannel,response);
                    }else if(read<0){
                        //对端链路关闭
                        key.cancel();
                        IOUtils.closeQuietly(socketChannel);
                    }else {
                        ;//读到0字节 忽略
                    }
                }
            }
        }

        private void doWrite(SocketChannel socketChannel, String response) throws IOException {
            if(response!=null && response.trim().length()>0){
                byte[] bytes = response.getBytes();
                ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
                byteBuffer.put(bytes);
                byteBuffer.flip();
                socketChannel.write(byteBuffer);
            }
        }
    }

}
